<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by an Apache 2.0 License.
See the COPYING file for details.
-->
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <!--

  Author: nicksantos@google.com (Nick Santos)
  -->
  <title>Closure Unit Tests - goog.testing.events</title>
  <script src="../../base.js"></script>
  <script>
    goog.require('goog.array');
    goog.require('goog.dom');
    goog.require('goog.math.Coordinate');
    goog.require('goog.string');
    goog.require('goog.testing.PropertyReplacer');
    goog.require('goog.testing.events');
    goog.require('goog.testing.jsunit');
    goog.require('goog.userAgent');


  </script>
</head>
<body>
<div id="root"></div>
<input id='testButton' type='input' value='Click Me' />
<div id='input'>Prevent Default these events:<br/></div>
<div id='log' style='position:absolute;right:0;top:0'>Logged events:</div>
<script type="text/javascript">
  var firedEventTypes;
  var firedEventCoordinates;
  var firedShiftKeys;
  var firedKeyCodes;
  var root = goog.dom.getElement('root');
  var log = goog.dom.getElement('log');
  var input = goog.dom.getElement('input');
  var testButton = goog.dom.getElement('testButton');
  var coordinate = new goog.math.Coordinate(123, 456);
  var stubs = new goog.testing.PropertyReplacer();

  function setUp() {
    stubs.reset();
    goog.events.removeAll();
    root.innerHTML = '';
    firedEventTypes = [];
    firedEventCoordinates = [];
    firedShiftKeys = [];
    firedKeyCodes = [];

    for (var key in goog.events.EventType) {
      goog.events.listen(root, goog.events.EventType[key], function(e) {
        firedEventTypes.push(e.type);
        var coord = new goog.math.Coordinate(e.clientX, e.clientY);
        firedEventCoordinates.push(coord);
        firedShiftKeys.push(!!e.shiftKey);
        firedKeyCodes.push(e.keyCode);
      });
    }
  }

  function tearDownPage() {
    for (var key in goog.events.EventType) {
      var type = goog.events.EventType[key];
      if (type == 'mousemove' || type == 'mouseout' || type == 'mouseover') {
        continue;
      }
      goog.dom.appendChild(input,
          goog.dom.createDom('label', null,
              goog.dom.createDom('input',
                  {'id': type, 'type': 'checkbox'}),
              type,
              goog.dom.createDom('br')));
      goog.events.listen(testButton, type, function(e) {
        if (goog.dom.getElement(e.type).checked) {
          e.preventDefault();
        }

        log.innerHTML += goog.string.subs('<br/>%s (%s, %s)',
            e.type, e.clientX, e.clientY);
      });
    }
  }

  function testMouseOver() {
    goog.testing.events.fireMouseOverEvent(root, null);
    goog.testing.events.fireMouseOverEvent(root, null, coordinate);
    assertEventTypes(['mouseover', 'mouseover']);
    assertCoordinates([new goog.math.Coordinate(), coordinate]);
  }

  function testMouseOut() {
    goog.testing.events.fireMouseOutEvent(root, null);
    goog.testing.events.fireMouseOutEvent(root, null, coordinate);
    assertEventTypes(['mouseout', 'mouseout']);
    assertCoordinates([new goog.math.Coordinate(), coordinate]);
  }

  function testClickSequence() {
    assertTrue(goog.testing.events.fireClickSequence(root));
    assertEventTypes(['mousedown', 'mouseup', 'click']);
  }

  function testClickSequenceWithCoordinate() {
    assertTrue(goog.testing.events.fireClickSequence(root, null, coordinate));
    assertCoordinates([coordinate, coordinate, coordinate]);
    assertArrayEquals([false, false, false], firedShiftKeys);
  }

  function testClickSequenceWithEventProperty() {
    assertTrue(goog.testing.events.fireClickSequence(
          root, null, undefined, { shiftKey: true }));
    assertArrayEquals([true, true, true], firedShiftKeys);
  }

  function testClickSequenceCancellingMousedown() {
    preventDefaultEventType('mousedown');
    assertFalse(goog.testing.events.fireClickSequence(root));
    assertEventTypes(['mousedown', 'mouseup', 'click']);
  }

  function testClickSequenceCancellingMousedownWithCoordinate() {
    preventDefaultEventType('mousedown');
    assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
    assertCoordinates([coordinate, coordinate, coordinate]);
  }

  function testClickSequenceCancellingMouseup() {
    preventDefaultEventType('mouseup');
    assertFalse(goog.testing.events.fireClickSequence(root));
    assertEventTypes(['mousedown', 'mouseup', 'click']);
  }

  function testClickSequenceCancellingMouseupWithCoordinate() {
    preventDefaultEventType('mouseup');
    assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
    assertCoordinates([coordinate, coordinate, coordinate]);
  }

  function testClickSequenceCancellingClick() {
    preventDefaultEventType('click');
    assertFalse(goog.testing.events.fireClickSequence(root));
    assertEventTypes(['mousedown', 'mouseup', 'click']);
  }

  function testClickSequenceCancellingClickWithCoordinate() {
    preventDefaultEventType('click');
    assertFalse(goog.testing.events.fireClickSequence(root, null, coordinate));
    assertCoordinates([coordinate, coordinate, coordinate]);
  }

  // For a double click, IE fires selectstart instead of the second mousedown,
  // but we don't simulate selectstart. Also, IE doesn't fire the second click.
  var DBLCLICK_SEQ = (goog.userAgent.IE ?
                      ['mousedown',
                       'mouseup',
                       'click',
                       'mouseup',
                       'dblclick'] :
                      ['mousedown',
                       'mouseup',
                       'click',
                       'mousedown',
                       'mouseup',
                       'click',
                       'dblclick']);


  var DBLCLICK_SEQ_COORDS = goog.array.repeat(coordinate, DBLCLICK_SEQ.length);

  function testDoubleClickSequence() {
    assertTrue(goog.testing.events.fireDoubleClickSequence(root));
    assertEventTypes(DBLCLICK_SEQ);
  }

  function testDoubleClickSequenceWithCoordinate() {
    assertTrue(goog.testing.events.fireDoubleClickSequence(root, coordinate));
    assertCoordinates(DBLCLICK_SEQ_COORDS);
  }

  function testDoubleClickSequenceCancellingMousedown() {
    preventDefaultEventType('mousedown');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root));
    assertEventTypes(DBLCLICK_SEQ);
  }

  function testDoubleClickSequenceCancellingMousedownWithCoordinate() {
    preventDefaultEventType('mousedown');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
    assertCoordinates(DBLCLICK_SEQ_COORDS);
  }

  function testDoubleClickSequenceCancellingMouseup() {
    preventDefaultEventType('mouseup');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root));
    assertEventTypes(DBLCLICK_SEQ);
  }

  function testDoubleClickSequenceCancellingMouseupWithCoordinate() {
    preventDefaultEventType('mouseup');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
    assertCoordinates(DBLCLICK_SEQ_COORDS);
  }

  function testDoubleClickSequenceCancellingClick() {
    preventDefaultEventType('click');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root));
    assertEventTypes(DBLCLICK_SEQ);
  }

  function testDoubleClickSequenceCancellingClickWithCoordinate() {
    preventDefaultEventType('click');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
    assertCoordinates(DBLCLICK_SEQ_COORDS);
  }

  function testDoubleClickSequenceCancellingDoubleClick() {
    preventDefaultEventType('dblclick');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root));
    assertEventTypes(DBLCLICK_SEQ);
  }

  function testDoubleClickSequenceCancellingDoubleClickWithCoordinate() {
    preventDefaultEventType('dblclick');
    assertFalse(goog.testing.events.fireDoubleClickSequence(root, coordinate));
    assertCoordinates(DBLCLICK_SEQ_COORDS);
  }

  function testKeySequence() {
    assertTrue(goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.ZERO));
    assertEventTypes(['keydown', 'keypress', 'keyup']);
  }

  function testKeySequenceCancellingKeydown() {
    preventDefaultEventType('keydown');
    assertFalse(goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.ZERO));
    if (goog.userAgent.IE) {
      assertEventTypes(['keydown', 'keyup']);
    } else {
      assertEventTypes(['keydown', 'keypress', 'keyup']);
    }
  }

  function testKeySequenceCancellingKeypress() {
    preventDefaultEventType('keypress');
    assertFalse(goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.ZERO));
    assertEventTypes(['keydown', 'keypress', 'keyup']);
  }

  function testKeySequenceCancellingKeyup() {
    preventDefaultEventType('keyup');
    assertFalse(goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.ZERO));
    assertEventTypes(['keydown', 'keypress', 'keyup']);
  }

  function testKeySequenceWithEscapeKey() {
    assertTrue(goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.ESC));
    if (goog.userAgent.WEBKIT && goog.userAgent.isVersion('525')) {
      assertEventTypes(['keydown', 'keyup']);
    } else {
      assertEventTypes(['keydown', 'keypress', 'keyup']);
    }
  }

  function testKeySequenceForMacActionKeysNegative() {
    stubs.set(goog.userAgent, 'GECKO', false);
    goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.C, {'metaKey': true});
    assertEventTypes(['keydown', 'keypress', 'keyup']);
  }

  function testKeySequenceForMacActionKeysPositive() {
    stubs.set(goog.userAgent, 'GECKO', true);
    stubs.set(goog.userAgent, 'MAC', true);
    goog.testing.events.fireKeySequence(
        root, goog.events.KeyCodes.C, {'metaKey': true});
    assertEventTypes(['keypress', 'keyup']);
  }

  function testKeySequenceForOptionKeysOnMac() {
    // Mac uses an option (or alt) key to type non-ASCII characters. This test
    // verifies we can emulate key events sent when typing such non-ASCII
    // characters.
    stubs.set(goog.userAgent, 'WEBKIT', true);
    stubs.set(goog.userAgent, 'MAC', true);

    var optionKeyCodes = [
      [0xc0, 0x00e6],  // option+'
      [0xbc, 0x2264],  // option+,
      [0xbd, 0x2013],  // option+-
      [0xbe, 0x2265],  // option+.
      [0xbf, 0x00f7],  // option+/
      [0x30, 0x00ba],  // option+0
      [0x31, 0x00a1],  // option+1
      [0x32, 0x2122],  // option+2
      [0x33, 0x00a3],  // option+3
      [0x34, 0x00a2],  // option+4
      [0x35, 0x221e],  // option+5
      [0x36, 0x00a7],  // option+6
      [0x37, 0x00b6],  // option+7
      [0x38, 0x2022],  // option+8
      [0x39, 0x00aa],  // option+9
      [0xba, 0x2026],  // option+;
      [0xbb, 0x2260],  // option+=
      [0xdb, 0x201c],  // option+[
      [0xdc, 0x00ab],  // option+\
      [0xdd, 0x2018],  // option+]
      [0x41, 0x00e5],  // option+a
      [0x42, 0x222b],  // option+b
      [0x43, 0x00e7],  // option+c
      [0x44, 0x2202],  // option+d
      [0x45, 0x00b4],  // option+e
      [0x46, 0x0192],  // option+f
      [0x47, 0x00a9],  // option+g
      [0x48, 0x02d9],  // option+h
      [0x49, 0x02c6],  // option+i
      [0x4a, 0x2206],  // option+j
      [0x4b, 0x02da],  // option+k
      [0x4c, 0x00ac],  // option+l
      [0x4d, 0x00b5],  // option+m
      [0x4e, 0x02dc],  // option+n
      [0x4f, 0x00f8],  // option+o
      [0x50, 0x03c0],  // option+p
      [0x51, 0x0153],  // option+q
      [0x52, 0x00ae],  // option+r
      [0x53, 0x00df],  // option+s
      [0x54, 0x2020],  // option+t
      [0x56, 0x221a],  // option+v
      [0x57, 0x2211],  // option+w
      [0x58, 0x2248],  // option+x
      [0x59, 0x00a5],  // option+y
      [0x5a, 0x03a9]   // option+z
    ];

    for (var i = 0; i < optionKeyCodes.length; ++i) {
      firedEventTypes = [];
      firedKeyCodes = [];
      var keyCode = optionKeyCodes[i][0];
      var keyPressKeyCode = optionKeyCodes[i][1];
      goog.testing.events.fireNonAsciiKeySequence(
          root, keyCode, keyPressKeyCode, {'altKey': true});
      assertEventTypes(['keydown', 'keypress', 'keyup']);
      assertArrayEquals([keyCode, keyPressKeyCode, keyCode], firedKeyCodes);
    }
  }

  var CONTEXTMENU_SEQ =
      goog.userAgent.WINDOWS ? ['mousedown', 'mouseup', 'contextmenu'] :
      goog.userAgent.GECKO ? ['mousedown', 'contextmenu', 'mouseup'] :
      ['mousedown', 'contextmenu'];

  function testContextMenuSequence() {
    assertTrue(goog.testing.events.fireContextMenuSequence(root));
    assertEventTypes(CONTEXTMENU_SEQ);
  }

  function testContextMenuSequenceWithCoordinate() {
    assertTrue(goog.testing.events.fireContextMenuSequence(root, coordinate));
    assertEventTypes(CONTEXTMENU_SEQ);
    assertCoordinates(goog.array.repeat(coordinate, CONTEXTMENU_SEQ.length));
  }

  function testContextMenuSequenceCancellingMousedown() {
    preventDefaultEventType('mousedown');
    assertFalse(goog.testing.events.fireContextMenuSequence(root));
    assertEventTypes(CONTEXTMENU_SEQ);
  }

  function testContextMenuSequenceCancellingMouseup() {
    preventDefaultEventType('mouseup');
    if (goog.userAgent.WINDOWS || goog.userAgent.GECKO) {
      assertFalse(goog.testing.events.fireContextMenuSequence(root));
    } else {
      assertTrue(goog.testing.events.fireContextMenuSequence(root));
    }
    assertEventTypes(CONTEXTMENU_SEQ);
  }

  function testContextMenuSequenceCancellingContextMenu() {
    preventDefaultEventType('contextmenu');
    assertFalse(goog.testing.events.fireContextMenuSequence(root));
    assertEventTypes(CONTEXTMENU_SEQ);
  }

  /**
   * Assert that the list of events given was fired, in that order.
   */
  function assertEventTypes(list) {
    assertArrayEquals(list, firedEventTypes);
  }

  /**
   * Assert that the list of event coordinates given was caught, in that order.
   */
  function assertCoordinates(list) {
    assertArrayEquals(list, firedEventCoordinates);
  }

  /** Prevent default the event of the given type on the root element. */
  function preventDefaultEventType(type) {
    goog.events.listen(root, type, preventDefault);
  }

  function preventDefault(e) {
    e.preventDefault();
  }
</script>
</body>
</html>
